package com.example.LightningController;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * Created with IntelliJ IDEA.
 * User: master
 * Date: 6/5/13
 * Time: 11:16 PM
 * To change this template use File | Settings | File Templates.
 */
public class SPPManager {

    public enum AccessType {
        ADD_NEW_DEVICE(1), OPEN_EXISTING_DEVICE(2);

        private int identificator;

        private AccessType(int i) {
            this.identificator = i;
        }

        public int getAccessType() {
            return identificator;
        }
    }

    private static final int REQUEST_ENABLE_BT = 2;
    SelectedDevice selectedDeviceListener;
    private BluetoothAdapter bluetoothAdapter;
    private Context context;
    private DatabaseManager databaseManager;
    private ConnectRunnable connector;
    OnNewZoneAdded onNewZoneAddedListener;
    Dialog availableDevicesDialog;
    private OutputStream outputStreamIdleObject;
    private InputReader inputStreamReader;

    public SPPManager(Context context, DatabaseManager databaseManager) {
        this.context = context;
        this.databaseManager = databaseManager;
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            return;
        }
    }

    public void setOnNewItemListener(OnNewZoneAdded onNewZoneAddedListener) {
        this.onNewZoneAddedListener = onNewZoneAddedListener;
    }

    public void setSelectedDeviceListener(SelectedDevice selectedDeviceListener) {
        this.selectedDeviceListener = selectedDeviceListener;
    }

    public Set<BluetoothDevice> searchForDevices() {
        if (bluetoothAdapter.isEnabled()) {
            Set<BluetoothDevice> devicesAvailable = bluetoothAdapter.getBondedDevices();
            if (devicesAvailable.isEmpty()) {
                informUserNoDevicesPaired();
            } else {
                return devicesAvailable;
            }
        } else {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            ((Activity) this.context).startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        return null;
    }

    private void informUserNoDevicesPaired() {
        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this.context);
        dialogBuilder.setMessage("No \"Paired\" devices");
        dialogBuilder.setPositiveButton("Search", new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int arg1) {
                dialog.dismiss();
            }
        });
        dialogBuilder.setOnCancelListener(new
                                                  DialogInterface.OnCancelListener() {

                                                      public void onCancel(DialogInterface dialog) {
                                                          dialog.dismiss();
                                                      }
                                                  });
        dialogBuilder.show();
    }

    public void pickADevice(Set<BluetoothDevice> devicesAvailable) {
        final BluetoothDevice[] selectedBluetoothDevice = new BluetoothDevice[1];
        final ListView view = new ListView(this.context);
        view.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        ArrayAdapter<BluetoothDevice> adapter =
                new ArrayAdapter(this.context, R.layout.devicesavailabletextview, devicesAvailable.toArray(new BluetoothDevice[devicesAvailable.size()])) {
                    @Override
                    public View getView(int position, View convertView, ViewGroup parent) {
                        TextView view = (TextView) super.getView(position, convertView, parent);
                        BluetoothDevice bluetoothDevice = (BluetoothDevice) getItem(position);
                        view.setText("\u2022 " + bluetoothDevice.getName() + "\n" + Html.fromHtml("&nbsp;&nbsp;") + bluetoothDevice.getAddress());
                        return view;
                    }
                };
        view.setAdapter(adapter);
        view.setOnItemClickListener(new
                                            AdapterView.OnItemClickListener() {

                                                public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
                                                    selectedBluetoothDevice[0] = ((BluetoothDevice) view.getItemAtPosition(position));
                                                    selectedDeviceListener.deviceSelected(selectedBluetoothDevice[0]);
                                                }
                                            });


        availableDevicesDialog = new Dialog(this.context);
        availableDevicesDialog.setTitle("Paired devices:");
        availableDevicesDialog.setContentView(view);
        availableDevicesDialog.setCancelable(true);
        availableDevicesDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                ((Activity) SPPManager.this.context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
                //To change body of implemented methods use File | Settings | File Templates.
            }
        });
        availableDevicesDialog.show();
    }

    public void pairDevice(final BluetoothDevice bluetoothDevice, final AccessType accessType) {
//        final ProgressDialog dialog = new ProgressDialog(this.context);
        try {
            connector = new ConnectRunnable(bluetoothDevice);
            connector.setConnectionEstablishedListener(new OnConnectionEstablishedListener() {
                @Override
                public void onConnectionEstablished() {
                    Log.i("activity_result", "connected!");

                    if (accessType.equals(AccessType.ADD_NEW_DEVICE)) {
                        ((Activity) SPPManager.this.context).runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //To change body of implemented methods use File | Settings | File Templates.
                                final EditText nameEditText = new EditText(SPPManager.this.context);

                                AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(SPPManager.this.context);
                                dialogBuilder.setMessage("Enter name to remember device");
                                dialogBuilder.setView(nameEditText);
                                dialogBuilder.setPositiveButton("Save", new DialogInterface.OnClickListener() {

                                    public void onClick(DialogInterface dialog, int arg1) {
                                        String deviceName = nameEditText.getText().toString();
                                        long id = SPPManager.this.databaseManager.insertIntoDatabase(deviceName, bluetoothDevice.getAddress());
                                        dialog.dismiss();

                                        Log.i("after_insertion", "" + id);

                                        SPPManager.this.onNewZoneAddedListener.onNewZoneAdded(id, deviceName, bluetoothDevice.getAddress());
                                        availableDevicesDialog.dismiss();
                                    }
                                });
                                dialogBuilder.setOnCancelListener(new
                                                                          DialogInterface.OnCancelListener() {

                                                                              public void onCancel(DialogInterface dialog) {
                                                                                  connector.cancel();
                                                                                  ((Activity) SPPManager.this.context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
                                                                                  dialog.dismiss();
                                                                              }
                                                                          });
                                dialogBuilder.show();

                            }
                        });

                    }
                }
            });

//                add connector listener, which will return true or false based on socket.isConnected();
//                dialog.show(this.context, "Kobler til", "Koblier til " + bluetoothDevice.getName() + " : " + bluetoothDevice.getAddress(),
//                        true, true,
//                        new DialogInterface.OnCancelListener() {
//
//                            public void onCancel(DialogInterface dialog) {
//                                connector.cancel();
//                            }
//                        });

            new Thread(connector).start();

        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvocationTargetException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

    private void closeSocket(BluetoothSocket openSocket) {
        try {
            openSocket.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    private void startListeningForInput(BluetoothSocket socket) {
        inputStreamReader = new InputReader(socket);
        new Thread(inputStreamReader).start();
    }

    private void startListeneningForOutput(BluetoothSocket socket) {
        outputStreamIdleObject = new OutputStream(socket);
        new Thread(outputStreamIdleObject).start();
    }

    public void transmitToDevice(String degrees) {
        outputStreamIdleObject.transmit(degrees);
    }

    public String getDevicesTemperature() {
        return inputStreamReader.getTemperature();
    }

    private class ConnectRunnable implements Runnable {
        private final BluetoothSocket socket;
        private OnConnectionEstablishedListener connectionEstablishedListener;

        public ConnectRunnable(BluetoothDevice device) throws IOException, InvocationTargetException, IllegalAccessException {
            Method m = null;
            try {
                m = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            socket = (BluetoothSocket) m.invoke(device, 1);
        }

        public void run() {
            try {
                bluetoothAdapter.cancelDiscovery();
                socket.connect();
            } catch (IOException connectException) {
                closeSocket(socket);
                return;
            }
            startListeningForInput(socket);
            startListeneningForOutput(socket);
            connectionEstablishedListener.onConnectionEstablished();
        }

        public void cancel() {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void setConnectionEstablishedListener(OnConnectionEstablishedListener connectionEstablishedListener) {
            this.connectionEstablishedListener = connectionEstablishedListener;
        }
    }

    public void setConnectionEstablishedListener(OnConnectionEstablishedListener connectionEstablishedListener) {
        this.connector.connectionEstablishedListener = connectionEstablishedListener;
    }

    public void setNewMessageListener(OnNewMessageListener newMessageListener){
        this.inputStreamReader.setNewMessageListener(newMessageListener);
    }

    private class OutputStream implements Runnable {

        private final BluetoothSocket socket;
        private BufferedWriter bufferedReader;

        public OutputStream(BluetoothSocket socket) {
            this.socket = socket;

        }

        @Override
        public void run() {
            try {
                final java.io.OutputStream output = socket.getOutputStream();
                bufferedReader = new BufferedWriter(new OutputStreamWriter(output, "UTF-8"));

//                while (true) {
//
//                    try {
//                        bufferedReader.write("1");
//                    } catch (IOException e) {
//                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
//                    }
//                    try {
//                        bufferedReader.newLine();
//                        bufferedReader.flush();
//                    } catch (IOException e) {
//                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
//                    }
//                    try {
//                        Thread.sleep(2000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
//                    }
//                    try {
//                        bufferedReader.write("02");
//                    } catch (IOException e) {
//                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
//                    }
//                    try {
//                        bufferedReader.newLine();
//                        bufferedReader.flush();
//                    } catch (IOException e) {
//                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
//                    }
//                }


//                bufferedReader.write("02");    //02, 1
//                bufferedReader.newLine();
//                bufferedReader.flush();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        public void transmit(String degrees) {
            //To change body of created methods use File | Settings | File Templates.
            try {
                bufferedReader.write(degrees);
                bufferedReader.newLine();
                bufferedReader.flush();
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

    private class InputReader implements Runnable {
        private OnNewMessageListener setNewMessageListener;
        private String extractedTemperature = null;

        private final BluetoothSocket socket;

        public InputReader(BluetoothSocket socket) {
            this.socket = socket;

        }

        @Override
        public void run() {
            try {
                final InputStream input = socket.getInputStream();
                final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
                String line;

                while ((line = bufferedReader.readLine()) != null) {
                    lineReadFromBluetoothDevice(line);
                    if(this.setNewMessageListener != null)
                    this.setNewMessageListener.onMessageListener(getTemperature());
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        public void cancel() {
            try {
                socket.close();
            } catch (IOException e) {
            }
        }

        public void lineReadFromBluetoothDevice(String line) {
            Log.d("data_transfer", "Mottok: " + line);
            extractTemperature(line);
        }

        private void extractTemperature(String line) {
            this.extractedTemperature = line.substring(line.indexOf("t: ")+3, line.length());
            Log.i("temperature", this.extractedTemperature);
        }

        public String getTemperature() {
            return this.extractedTemperature;
        }

        public void setNewMessageListener(OnNewMessageListener listener){
            this.setNewMessageListener = listener;
        }
    }

    public void closeDeviceConnection() {
        this.connector.cancel();
    }
}
